#!/usr/bin/env python
#
#       Server.py
#       
#       Copyright 2009 Ben Davis <its.hip@gmail.com>
#       
#       This program is free software; you can redistribute it and/or modify
#       it under the terms of the GNU General Public License as published by
#       the Free Software Foundation; either version 2 of the License, or
#       (at your option) any later version.
#       
#       This program is distributed in the hope that it will be useful,
#       but WITHOUT ANY WARRANTY; without even the implied warranty of
#       MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
#       GNU General Public License for more details.
#       
#       You should have received a copy of the GNU General Public License
#       along with this program; if not, write to the Free Software
#       Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston,
#       MA 02110-1301, USA.

import random
import socket
import sys
import threading
import time

import Clients
import Database
import Maps
import Options
import Orders
import Parser
import Players
import Ships
import ToClient
import ToServer

def main():
    try:
        HOST = ''
        try:
            PORT = int(sys.argv[1])
        except IndexError:
            PORT = 7059
        try:
            NOTES = sys.argv[2]
        except IndexError:
            NOTES = "Anyone can join!"   
        

        print "Starting server on port", PORT, "("+NOTES+")"
        if NOTES == "debugplz":
            Options.DEBUG = True
            print "Server running in debug."
        listener = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
        listener.bind((HOST, PORT))
        listener.listen(1)
        listener.settimeout(0.01)
        
        players = Players.Players()
        map = Maps.Map()
        clients = Clients.Clients()
        
        database = Database.Database(PORT, NOTES)
        if Options.REGISTER:
            auto_register = Database.AutoRegister(database)
            auto_register.start()
        
        chosen = []
        running = False
        haschosen= {}
        
        print "Running."
        
        ticked = False
        ticker = 0
        
        
        while True:
            try:
                # Listen for a new client
                s, address = listener.accept()
                
                print "new client!"
                
                '''new_spec = Spectators.Spectator(address[0])
                new_spec.number = len(spectators)
                spectators.append(new_spec)'''
                
                # Add a new player for client. For the moment, name them
                # by IP address
                new_player = Players.Player(address[0])
                new_player.number = len(players)
                players.append(new_player)
                
                nametemp = 0
                for pguy in players:
                    if players[pguy].origname == new_player.name and players[pguy] != new_player:
                        nametemp +=1
                if nametemp > 0:
                    new_player.setname((new_player.name + "("+ str(nametemp)+ ")"));
                        
                new_player.setaddress(address[0])
                #FLAG: Maybe need to edit the last-added player rather than new_player?
                
                '''# Give them a ship to play with
                #while len(new_player.ships.values()) < 1:
                    #x, y = random.randint(0, Map.WIDTH - 1), random.randint(0, Map.HEIGHT - 1)
                    #for player in players.values():
                        #for ship in player.ships.values():
                            #if ship.x == x and ship.y == y:
                                #break
                    #else:
                        #new_player.ships.append(Ships.Pawn(new_player, x, y, random.randint(0, 7)))'''
                if Options.DEBUG:
                    if len(players) == 1:
                        for x, y in ((8, 4), (12, 4), (10, 2), (10, 6)):
                            new_player.ships.append(Ships.Pawn(new_player, x, y, 4))
                        new_player.ships.append(Ships.King(new_player, 10, 4, 4))
                    if len(players) == 2:
                        for x, y in ((8, 19), (8, 23), (10, 21), (12, 19), (12, 23)):
                            new_player.ships.append(Ships.Pawn(new_player, x, y, 0))
                    # If this is the first player
                    if len(players) == 1:
                        # It's their turn
                        players.turn = new_player.key()
                        for ship in players[players.turn].ships.values():
                            ship.steam += ship.steam_prod
                            if ship.steam > ship.steam_max:
                                ship.steam = ship.steam_max
                else:
                            
                    if len(players) == 1:
                        # It's their turn
                        players.turn = new_player.key()
                        '''if Options.DEBUG:
                            for ship in players[players.turn].ships.values():
                                ship.steam += ship.steam_prod
                                if ship.steam > ship.steam_max:
                                    ship.steam = ship.steam_max'''#duh.
                    
                #print "ping1"
                # Create a new client object for new connection
                client = Clients.Client(s, new_player)
                client.start()
                #print "ping2"
                client.parser = Parser.Parser(client)
                # Notify existing clients of the new player
                clients.send(ToClient.AddPlayer(client.player))
                # Add to the list of clients
                clients.append(client)
                print new_player.name, address, "connected"
                #print "ping3"
                #client.send(ToClient.Connected(client.player))
        
                # Sync players/map data with new client
                client.send(ToClient.Sync(client.player))
                
                if Options.DEBUG == False:
                    #print "ping4"
                    client.send(ToClient.GoLobby())
                    print "Hellothere, golobbyplz"
                    #print "ping5"
                    
                    print haschosen
                    print chosen
                    print running
                
                database.register()
                
            except (socket.error, socket.timeout):
                pass
            
            '''if ticker >= 2000:
                ticker = 0
                ticked = True
                print "-----------------------------tick'd--------------------------------------"
                for lol in clients[:]:
                    if not lol.disconnected:
                        if len(chosen) > 1:
                            lol.send(ToClient.Sync(lol.player))
            else:
                if ticker == 1:
                    ticked = False
                ticker += 1'''
                
            
            
            
            # Receive data from clients
            for client in clients[:]:
                #try:
                if not client.disconnected:
                    data = client.poll()
                    if data:
                        data(client)
                    if Options.DEBUG == False:
                        if client.chosen == "":
                            haschosen[client.player.key()] = False
                        
                        if client.chosen != "" and running == False and haschosen[client.player.key()] != True:
                            #print client.chosen
                            if client.chosen == 0 and len(chosen) > 0: #if we picked 0, and the other person has picked..
                                if chosen[0] == 0:#if they picked 0
                                    print "Not "+client.player.name+" picked rand."
                                    chosen[0] = random.randint(1,2)#give them 1 or 2
                                
                                if chosen[0] != 1 :
                                    if chosen[0] != 2:
                                        chosen[0] = 2 #flag with red, I guess.
                                        print "RANDOM FAILED"
                                
                                if chosen[0] == 1:#and then we'll have what they didn't have, whatever their choice.
                                    client.chosen = 2
                                elif chosen[0] == 2:
                                    client.chosen = 1
                            
                            chosen.append(client.chosen) #add to chosen either way
                            #appends as 1 more than once
                            client.player.type="player"
                            haschosen[client.player.key()] = True
                            
                            if len(chosen) > 1: #if both have chosen
                                #print "Chosen > 1:", len(chosen), chosen
                                
                                for lolclient in clients[:]:
                                    if lolclient.chosen != "":
                                        lolclient.player.setnum(lolclient.chosen-1)
                                    if lolclient.chosen == 1:# add some ships
                                        for x, y in ((8, 4), (12, 4), (10, 2), (10, 6)):
                                            lolclient.player.ships.append(Ships.Pawn(lolclient.player, x, y, 4))
                                        lolclient.player.ships.append(Ships.King(lolclient.player, 10, 4, 4))
                                        
                                        players.turn = lolclient.player.key() #it's p1's turn first. If this works.
                                        
                                    elif lolclient.chosen == 2:#and again
                                        for x, y in ((8, 19), (8, 23), (10, 21), (12, 19), (12, 23)):
                                            lolclient.player.ships.append(Ships.Pawn(lolclient.player, x, y, 0))
                                            
                                    for ship in lolclient.player.ships.values(): #juice up the ships
                                        ship.steam += ship.steam_prod
                                        if ship.steam > ship.steam_max:
                                            ship.steam = ship.steam_max
                                
                                print "Starting the game!"
                                database.register()
                                running = True
                       
                            
                                for lol in clients[:]:
                                    if not lol.disconnected:
                                        lol.send(ToClient.Kill())
                                        lol.send(ToClient.Sync(lol.player))
                    
                else:
                    print "----------------------------------"
                    print "FUCK YOU ALL"
                    print len(players)
                    print len(clients)
                    print client.player.name, "disconnected"
                    print client.player.type, client.player, "\n"
                    
                    if Options.DEBUG == False:
                        if client.player.type != 0:
                            #we don't care if a spectator leaves, BUT
                            #if it's a player, we need to reset hte other player to lobby.
                            #probably a message about what happened would be nice too.
                            chosen = []
                            haschosen = {} # there was no choice.
                            running = False #not runing any more plz.
                            print chosen
                            print haschosen
                            print running
                            
                            for lolhi in clients[:]:#sort out everyone else
                                if lolhi.player.type == "player":#first, reset other player
                                    lolhi.player.type = ""
                                    lolhi.chosen = ""
                                    print lolhi.player
                                    #players.remove(lolhi.player)
                                    '''for ship in lolhi.player.ships: # delete their ships otherwise it will get silly.
                                        for target in lolhi.player.ships.values():'''
                                lolhi.send(ToClient.GoLobby()) #kick everyone to lobby
                            
                            
                            
                            if client.player.key() == players.turn:
                                # Change to next player
                                players.next()
                            #might fx p1 leave, p2 die thing
                            
                            
                        del(players[client.player.key()]) #de-player the one who left.
                        print "DELETED"
                            
                                    
                                
                        clients.remove(client)
                        print len(players), "players,", len(clients), "clients."
                        
                    else:
                        if client.player.key() == players.turn:
                            # Change to next player
                            players.next()
                        clients.remove(client)
                        del(players[client.player.key()])
                            
                    #print len(players), "players"
                    #if len(players) > 0:
                    clients.send(ToClient.NewTurn(players.turn))
                    clients.send(ToClient.RemovePlayer(client.player))
                    
                    database.register()
                #except socket.error:
                #    # If it's this client's player's turn
                #    if client.player == players.turn:
                #        # Change to next player
                #        players.next()
                #    clients.remove(client)
                #    del(players[client.player.key()])
                #    if len(players) > 0:
                #        clients.send(ToClient.NewTurn(players.turn))
                #        clients.send(ToClient.RemovePlayer(client.player))
                #    database.register()
        raise SystemExit
                        
    except (KeyboardInterrupt, SystemExit):
        for client in clients[:]:
            client.send(ToClient.Kick("Server shutting down."))
        listener.close()
        clients.close()
        if Options.REGISTER:
            auto_register.join()
            database.unregister()
    
if __name__ == "__main__": main()
